package com.apidoc.core;

import com.apidoc.annotation.ApiOperation;
import com.apidoc.annotation.ApiParam;
import com.apidoc.config.ApiDocProperties;
import com.apidoc.model.ApiDocInfo;
import com.apidoc.model.ControllerInfo;
import com.apidoc.model.ApiInfo;
import com.apidoc.model.ParameterInfo;
import org.reflections.Reflections;
import org.reflections.scanners.Scanners;
import org.reflections.util.ClasspathHelper;
import org.reflections.util.ConfigurationBuilder;
import org.reflections.util.FilterBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;

@Component
public class ApiDocScanner {
    private final ApiDocProperties properties;
    private ApiDocInfo apiDocInfo; // 存储扫描后的所有文档数据

    @Autowired
    public ApiDocScanner(ApiDocProperties properties) {
        this.properties = properties;
    }

    /**
     * 扫描API信息并返回
     */
    public ApiDocInfo scan() {
        apiDocInfo = new ApiDocInfo();
        List<ControllerInfo> controllerInfos = new ArrayList<>();

        // 1. 反射扫描指定包下的 @Controller/@RestController 类
        ConfigurationBuilder cfg = new ConfigurationBuilder()
                .filterInputsBy(new FilterBuilder()
                        .includePackage(properties.getBasePackage()))   // 只保留配置的基础包及其子包
                .setUrls(ClasspathHelper.forPackage(properties.getBasePackage()))
                .setScanners(Scanners.TypesAnnotated);

        Reflections reflections = new Reflections(cfg);
        // 2. 获取所有带 @Controller 或 @RestController 注解的类
        Set<Class<?>> controllerClasses = reflections.getTypesAnnotatedWith(Controller.class);
        Set<Class<?>> restControllerClasses = reflections.getTypesAnnotatedWith(RestController.class);
        controllerClasses.addAll(restControllerClasses);

        // 3. 遍历每个控制器，解析接口信息
        for (Class<?> controllerClass : controllerClasses) {
            ControllerInfo controllerInfo = new ControllerInfo();
            // 3.1 解析控制器基础路径（类上的 @RequestMapping）
            String basePath = getControllerBasePath(controllerClass);
            controllerInfo.setClassName(controllerClass.getName()); // 完整类名
            controllerInfo.setSimpleName(controllerClass.getSimpleName()); // 简单类名
            controllerInfo.setBasePath(basePath); // 基础路径（如 /api/user）

            // 3.2 解析控制器中的所有接口方法
            List<ApiInfo> apiInfos = parseControllerMethods(controllerClass, basePath);
            controllerInfo.setApis(apiInfos);

            controllerInfos.add(controllerInfo);
        }

        apiDocInfo.setControllers(controllerInfos);
        System.out.println("扫描完成：共发现 " + controllerInfos.size() + " 个控制器，" + calculateTotalApis() + " 个接口");

        return apiDocInfo;
    }

    /**
     * 解析控制器类上的 @RequestMapping，获取基础路径
     */
    private String getControllerBasePath(Class<?> controllerClass) {
        if (controllerClass.isAnnotationPresent(RequestMapping.class)) {
            RequestMapping requestMapping = controllerClass.getAnnotation(RequestMapping.class);
            if (requestMapping.value().length > 0) {
                return normalizePath(requestMapping.value()[0]); // 取第一个路径并规范化
            }
        }
        return ""; // 无基础路径时返回空字符串
    }

    /**
     * 解析控制器中的方法，获取接口信息（路径、方法、参数等）
     */
    private List<ApiInfo> parseControllerMethods(Class<?> controllerClass, String basePath) {
        List<ApiInfo> apiInfos = new ArrayList<>();
        Method[] methods = controllerClass.getDeclaredMethods(); // 获取所有方法

        for (Method method : methods) {
            // 只处理带 @GetMapping/@PostMapping/@PutMapping/@DeleteMapping 的方法
            if (!isHttpMethodAnnotation(method)) {
                continue;
            }

            ApiInfo apiInfo = new ApiInfo();
            // 3.2.1 获取 HTTP 方法（GET/POST/PUT/DELETE）
            String httpMethod = getHttpMethod(method);
            // 3.2.2 获取方法路径（拼接基础路径）
            String methodPath = getMethodPath(method);
            String fullPath = combinePaths(basePath, methodPath); // 完整路径

            // 3.2.3 填充接口信息
            apiInfo.setHttpMethod(httpMethod);
            apiInfo.setPath(fullPath);
            apiInfo.setDescription(getApiDescription(method));
            apiInfo.setReturnType(getFriendlyTypeName(method.getReturnType()));
            apiInfo.setParameters(parseMethodParameters(method));

            apiInfos.add(apiInfo);
        }

        return apiInfos;
    }

    /**
     * 判断方法是否带 HTTP 方法注解
     */
    private boolean isHttpMethodAnnotation(Method method) {
        return method.isAnnotationPresent(GetMapping.class) ||
                method.isAnnotationPresent(PostMapping.class) ||
                method.isAnnotationPresent(PutMapping.class) ||
                method.isAnnotationPresent(DeleteMapping.class) ||
                method.isAnnotationPresent(RequestMapping.class);
    }

    /**
     * 获取 HTTP 方法（GET/POST 等）
     */
    private String getHttpMethod(Method method) {
        if (method.isAnnotationPresent(GetMapping.class)) return "GET";
        if (method.isAnnotationPresent(PostMapping.class)) return "POST";
        if (method.isAnnotationPresent(PutMapping.class)) return "PUT";
        if (method.isAnnotationPresent(DeleteMapping.class)) return "DELETE";
        if (method.isAnnotationPresent(RequestMapping.class)) {
            RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
            if (requestMapping.method().length > 0) {
                return requestMapping.method()[0].name();
            }
        }
        return "UNKNOWN";
    }

    /**
     * 获取方法路径（如 /{id}）
     */
    private String getMethodPath(Method method) {
        if (method.isAnnotationPresent(GetMapping.class)) {
            return getPathFromAnnotation(method.getAnnotation(GetMapping.class).value());
        } else if (method.isAnnotationPresent(PostMapping.class)) {
            return getPathFromAnnotation(method.getAnnotation(PostMapping.class).value());
        } else if (method.isAnnotationPresent(PutMapping.class)) {
            return getPathFromAnnotation(method.getAnnotation(PutMapping.class).value());
        } else if (method.isAnnotationPresent(DeleteMapping.class)) {
            return getPathFromAnnotation(method.getAnnotation(DeleteMapping.class).value());
        } else if (method.isAnnotationPresent(RequestMapping.class)) {
            return getPathFromAnnotation(method.getAnnotation(RequestMapping.class).value());
        }
        return "";
    }

    /**
     * 从注解中获取路径
     */
    private String getPathFromAnnotation(String[] values) {
        if (values != null && values.length > 0 && !values[0].isEmpty()) {
            return normalizePath(values[0]);
        }
        return "";
    }

    /**
     * 规范化路径（确保以/开头，避免重复//）
     */
    private String normalizePath(String path) {
        if (path == null || path.isEmpty()) {
            return "";
        }
        return path.startsWith("/") ? path : "/" + path;
    }

    /**
     * 合并基础路径和方法路径
     */
    private String combinePaths(String basePath, String methodPath) {
        if (basePath.isEmpty()) {
            return methodPath;
        }
        if (methodPath.isEmpty()) {
            return basePath;
        }
        // 处理基础路径以/结尾的情况
        if (basePath.endsWith("/")) {
            return basePath + (methodPath.startsWith("/") ? methodPath.substring(1) : methodPath);
        }
        return basePath + methodPath;
    }

    /**
     * 解析方法参数（@RequestParam/@PathVariable/@RequestBody等）
     */
    private List<ParameterInfo> parseMethodParameters(Method method) {
        List<ParameterInfo> paramInfos = new ArrayList<>();
        Parameter[] parameters = method.getParameters();
        // DEFAULT_NONE的实际值，来自Spring源码
        final String DEFAULT_NONE_VALUE = "\n\t\t\n\t\t\n\uE000\uE001\uE002\n\t\t\t\t\n";

        for (Parameter param : parameters) {
            ParameterInfo paramInfo = new ParameterInfo();
            paramInfo.setName(param.getName());
            paramInfo.setType(getFriendlyTypeName(param.getType()));

            // 处理自定义 @ApiParam 注解
            if (param.isAnnotationPresent(ApiParam.class)) {
                ApiParam apiParam = param.getAnnotation(ApiParam.class);
                if (!apiParam.value().isEmpty()) {
                    paramInfo.setDescription(apiParam.value());
                }
                paramInfo.setRequired(apiParam.required());
                if (!apiParam.defaultValue().isEmpty()) {
                    paramInfo.setDefaultValue(apiParam.defaultValue());
                }
            }

            // 处理带注解的参数
            if (param.isAnnotationPresent(RequestParam.class)) {
                RequestParam requestParam = param.getAnnotation(RequestParam.class);
                paramInfo.setParameterType("QUERY");
                // 如果 @ApiParam 没有设置 required，则使用 @RequestParam 的设置
                if (!param.isAnnotationPresent(ApiParam.class) ||
                        param.getAnnotation(ApiParam.class).value().isEmpty()) {
                    paramInfo.setRequired(requestParam.required());
                }
                // 如果 @ApiParam 没有设置描述，则使用 @RequestParam 的设置
                if (paramInfo.getDescription() == null || paramInfo.getDescription().isEmpty()) {
                    paramInfo.setDescription(requestParam.value().isEmpty() ? null : requestParam.value());
                }
                // 如果 @ApiParam 没有设置默认值，则使用 @RequestParam 的设置
                if (paramInfo.getDefaultValue() == null || paramInfo.getDefaultValue().isEmpty()) {
                    paramInfo.setDefaultValue(requestParam.defaultValue().equals(DEFAULT_NONE_VALUE) ?
                            null : requestParam.defaultValue());
                }
            } else if (param.isAnnotationPresent(PathVariable.class)) {
                PathVariable pathVariable = param.getAnnotation(PathVariable.class);
                paramInfo.setParameterType("PATH");
                // 如果 @ApiParam 没有设置 required，则使用 @PathVariable 的设置
                if (!param.isAnnotationPresent(ApiParam.class) ||
                        !param.getAnnotation(ApiParam.class).value().isEmpty()) {
                    paramInfo.setRequired(pathVariable.required());
                }
                // 如果 @ApiParam 没有设置描述，则使用 @PathVariable 的设置
                if (paramInfo.getDescription() == null || paramInfo.getDescription().isEmpty()) {
                    paramInfo.setDescription(pathVariable.value().isEmpty() ? null : pathVariable.value());
                }
            } else if (param.isAnnotationPresent(RequestBody.class)) {
                RequestBody requestBody = param.getAnnotation(RequestBody.class);
                paramInfo.setParameterType("BODY");
                // 如果 @ApiParam 没有设置 required，则使用 @RequestBody 的设置
                if (!param.isAnnotationPresent(ApiParam.class) ||
                        !param.getAnnotation(ApiParam.class).value().isEmpty()) {
                    paramInfo.setRequired(requestBody.required());
                }
            } else if (param.isAnnotationPresent(RequestHeader.class)) {
                RequestHeader requestHeader = param.getAnnotation(RequestHeader.class);
                paramInfo.setParameterType("HEADER");
                // 如果 @ApiParam 没有设置 required，则使用 @RequestHeader 的设置
                if (!param.isAnnotationPresent(ApiParam.class) ||
                        !param.getAnnotation(ApiParam.class).value().isEmpty()) {
                    paramInfo.setRequired(requestHeader.required());
                }
                // 如果 @ApiParam 没有设置描述，则使用 @RequestHeader 的设置
                if (paramInfo.getDescription() == null || paramInfo.getDescription().isEmpty()) {
                    paramInfo.setDescription(requestHeader.value().isEmpty() ? null : requestHeader.value());
                }
                // 如果 @ApiParam 没有设置默认值，则使用 @RequestHeader 的设置
                if (paramInfo.getDefaultValue() == null || paramInfo.getDefaultValue().isEmpty()) {
                    paramInfo.setDefaultValue(requestHeader.defaultValue().equals(DEFAULT_NONE_VALUE) ?
                            null : requestHeader.defaultValue());
                }
            }
            // 其他参数处理逻辑保持不变
            else if (MultipartFile.class.isAssignableFrom(param.getType())) {
                paramInfo.setParameterType("FORM");
                paramInfo.setDescription("文件上传参数");
            } else if (SseEmitter.class.isAssignableFrom(param.getType())) {
                paramInfo.setParameterType("SSE");
                paramInfo.setDescription("SSE连接参数");
            } else {
                inferDefaultParameterType(paramInfo, param.getType());
            }

            paramInfos.add(paramInfo);
        }

        return paramInfos;
    }

    /**
     * 获取接口描述 - 优先使用 @ApiOperation 注解
     */
    private String getApiDescription(Method method) {
        // 检查是否有自定义的 @ApiOperation 注解
        if (method.isAnnotationPresent(ApiOperation.class)) {
            ApiOperation apiOperation = method.getAnnotation(ApiOperation.class);
            if (!apiOperation.value().isEmpty()) {
                return apiOperation.value();
            }
        }
        // 默认描述
        return "接口：" + method.getName();
    }

    /**
     * 计算总接口数
     */
    private int calculateTotalApis() {
        if (apiDocInfo == null || apiDocInfo.getControllers() == null) {
            return 0;
        }
        return apiDocInfo.getControllers().stream()
                .filter(controller -> controller.getApis() != null)
                .mapToInt(controller -> controller.getApis().size())
                .sum();
    }

    /**
     * 按MVC规则推断无注解参数的类型
     */
    private void inferDefaultParameterType(ParameterInfo paramInfo, Class<?> paramType) {
        if (paramType.isPrimitive() || String.class.isAssignableFrom(paramType)
                || Number.class.isAssignableFrom(paramType) || Boolean.class == paramType) {
            // 基本类型、String、数字、布尔 → 推断为Query参数
            paramInfo.setParameterType("QUERY");
            paramInfo.setRequired(false);
        } else if (paramType.isArray() || Collection.class.isAssignableFrom(paramType)) {
            // 数组或集合 → 推断为Query多值参数
            paramInfo.setParameterType("QUERY");
            paramInfo.setRequired(false);
            paramInfo.setDescription("集合类型参数");
        } else {
            // 复杂对象 → 推断为Body参数
            paramInfo.setParameterType("BODY");
            paramInfo.setRequired(false);
            paramInfo.setDescription("复杂对象参数");
        }
    }

    /**
     * 将类名转换为友好名称
     */
    private String getFriendlyTypeName(Class<?> type) {
        if (type.isArray()) {
            return getFriendlyTypeName(type.getComponentType()) + "[]";
        }
        if (type.isAnonymousClass()) {
            return "Anonymous";
        }
        // 处理常见的容器类型
        String simpleName = type.getSimpleName();
        if (Collection.class.isAssignableFrom(type)) {
            return simpleName;
        }
        return simpleName;
    }
}
